From 9f45c37be74fb601653b787875b18c2a3352e69a Mon Sep 17 00:00:00 2001 From: Kristian Rietveld Date: Sun, 6 Nov 2011 09:25:16 +0100 Subject: [PATCH] quartz: Process motion events within windows bounds without window set When an NSEvent does not have the window field set, we already assumed the event was not for us and discarded it. But for NSMouseMoved events we now make an exception, because such events generated after using/clicking the main menu bar have the window field set to NULL while the application window still has focus. We used to experience a loss of motion events after using the menu bar, this could be seen in buttons that stopped prelighting and first clicks often being ignored unless you clicked somewhere else first. These issues are fixed by this patch. --- gdk/quartz/gdkevents-quartz.c | 64 +++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/gdk/quartz/gdkevents-quartz.c b/gdk/quartz/gdkevents-quartz.c index 22a8f285c5..3ef3e0f243 100644 --- a/gdk/quartz/gdkevents-quartz.c +++ b/gdk/quartz/gdkevents-quartz.c @@ -57,6 +57,12 @@ static GdkModifierType current_button_state; static void append_event (GdkEvent *event, gboolean windowing); +static GdkWindow *find_toplevel_under_pointer (GdkDisplay *display, + NSPoint screen_point, + gint *x, + gint *y); + + void _gdk_quartz_events_init (void) { @@ -329,19 +335,34 @@ get_toplevel_from_ns_event (NSEvent *nsevent, gint *x, gint *y) { - GdkQuartzView *view; GdkWindow *toplevel; - NSPoint point; - view = (GdkQuartzView *)[[nsevent window] contentView]; + if ([nsevent window]) + { + GdkQuartzView *view; + NSPoint point; - toplevel = [view gdkWindow]; + view = (GdkQuartzView *)[[nsevent window] contentView]; - point = [nsevent locationInWindow]; - *screen_point = [[nsevent window] convertBaseToScreen:point]; + toplevel = [view gdkWindow]; - *x = point.x; - *y = toplevel->height - point.y; + point = [nsevent locationInWindow]; + *screen_point = [[nsevent window] convertBaseToScreen:point]; + + *x = point.x; + *y = toplevel->height - point.y; + } + else + { + /* Fallback used when no NSWindow set. This happens e.g. when + * we allow motion events without a window set in gdk_event_translate() + * that occur immediately after the main menu bar was clicked/used. + */ + *screen_point = [NSEvent mouseLocation]; + toplevel = find_toplevel_under_pointer (_gdk_display, + *screen_point, + x, y); + } return toplevel; } @@ -1164,10 +1185,33 @@ gdk_event_translate (GdkEvent *event, nswindow = [nsevent window]; - /* Ignore events for no window or ones not created by GDK. */ - if (!nswindow || ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]]) + /* Ignore events for windows not created by GDK. */ + if (nswindow && ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]]) return FALSE; + /* Ignore events for ones with no windows */ + if (!nswindow) + { + GdkWindow *toplevel = NULL; + + if (event_type == NSMouseMoved) + { + /* Motion events received after clicking the menu bar do not have the + * window field set. Instead of giving up on the event immediately, + * we first check whether this event is within our window bounds. + */ + NSPoint screen_point = [NSEvent mouseLocation]; + gint x_tmp, y_tmp; + + toplevel = find_toplevel_under_pointer (_gdk_display, + screen_point, + &x_tmp, &y_tmp); + } + + if (!toplevel) + return FALSE; + } + /* Ignore events and break grabs while the window is being * dragged. This is a workaround for the window getting events for * the window title. -- 2.30.2